#pragma once

#include "LatoolException.h"

namespace LatoolNet {

	using namespace System;

	///
	///<summary>
	/// This class factorizes/solves a set of linear equations. 
	/// For non-symmetric/non-hermitian matrix, LAPACK's LU factorization 
	/// function is called.  For symmetric/hermitian matrix, LAPACK's 
	/// Cholesky factorization function is called.
	///</summary>
	public ref class LinearEquation {
	private:
		LinearEquation(){};

		static void Factorize(IDoubleMatrix ^ a) {
			if (a->IsFactorized == false) {
				a->Factorize();
			}
		};
		static void Factorize(IComplexMatrix ^ a) {
			if (a->IsFactorized == false) {
				a->Factorize();
			}
		};

		static void Solve(IDoubleMatrix ^ a, IDoubleMatrix ^ b) {
			if (a->RowNum != a->ColNum) {
				throw gcnew LatoolException("Matrix size m != n is not supported."); 
			}
			if (a->IsFactorized == true) {
				a->Solve(b);
			} else {
				a->SolveWithSimpleDriver(b);
			}
		};
		static void Solve(IComplexMatrix ^ a, IComplexMatrix ^ b) {
			if (a->RowNum != a->ColNum) {
				throw gcnew LatoolException("Matrix size m != n is not supported."); 
			}
			if (a->IsFactorized == true) {
				a->Solve(b);
			} else {
				a->SolveWithSimpleDriver(b);
			}
		};

	public:

		///
		///<summary>
		/// Factorizes a matrix. The result is overwritten to the passed matrix. 
		///</summary>
		///
		static void Factorize(Matrix ^ a) {
			Factorize(a->GetInternalMatrix());
		};

		///
		///<summary>
		/// Solve a system of linear equation. 
		/// If passed matrix is not factorized yet, this method factorizes it first 
		/// then solves. Matrix b can contain multiple vectors. 
		///</summary>
		///
		static void Solve(Matrix ^ a, Matrix ^ b) {
			Solve(a->GetInternalMatrix(), b->GetInternalMatrix());
		};

		///
		///<summary>
		/// Factorizes a complex matrix. The result is overwritten to the passed matrix. 
		///</summary>
		///
		static void Factorize(ComplexMatrix ^ a) {
			Factorize(a->GetInternalMatrix());
		};

		///
		///<summary>
		/// Solve a system of linear equation. 
		/// If passed matrix is not factorized yet, this method factorizes it first 
		/// then solves. Matrix b can contain multiple vectors. 
		///</summary>
		///
		static void Solve(ComplexMatrix ^ a, ComplexMatrix ^ b) {
			Solve(a->GetInternalMatrix(), b->GetInternalMatrix());
		};
	};
}
